package serverSide;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

import org.json.simple.JSONObject;

import serverSide.GameController.*;

import clientSide.*;

public class Server {
	public final static int SUBJECT_KEY = 0;
	public final static int SUBJECT_VALUE_SIGNIN = 1;
	public final static int SUBJECT_SIGNIN_KEY_ISACCEPTED = 10;
	public final static int SUBJECT_SIGNIN_VALUE_ACCEPTED = 100;
	public final static int SUBJECT_SIGNIN_VALUE_NOTACCEPTED = 101;
	public final static int SUBJECT_SIGNIN_KEY_PASSWORD = 11;
	public final static int SUBJECT_SIGNIN_KEY_USERNAME = 12;
	public final static int SUBJECT_VALUE_SIGNUP = 2;
	public final static int SUBJECT_SIGNUP_KEY_USERNAME = 21;
	public final static int SUBJECT_SIGNUP_KEY_PASSWORD = 22;
	public final static int SUBJECT_SIGNUP_KEY_ISCREATED = 20;
	public final static int SUBJECT_SIGNUP_VALUE_CREATED = 201;
	public final static int SUBJECT_SIGNUP_VALUE_NOTCREATED = 202;
	public final static int SUBJECT_VALUE_GAMEREQUEST = 3;
	public final static int SUBJECT_GAMEREQUEST_KEY_TYPE = 31;
	public final static int SUBJECT_GAMEREQUEST_VALUE_TICTACTOI = 310;
	public final static int SUBJECT_GAMEREQUEST_KEY_STATE = 32;
	public final static int SUBJECT_GAMEREQUEST_VALUE_WAIT = 320;
	public final static int SUBJECT_GAMEREQUEST_VALUE_GO = 321;
	public final static int SUBJECT_GAMEREQUEST_KEY_PLAYER1 = 33;
	public final static int SUBJECT_GAMEREQUEST_KEY_PLAYER2 = 34;
	public final static int SUBJECT_GAMEREQUEST_KEY_USER = 35;
	public final static int SUBJECT_VALUE_GAMING = 4;
	public final static int SUBJECT_GAMING_KEY_TYPE = 41;
	public final static int SUBJECT_GAMING_VALUE_TICTACTOI = 410;
	public final static int SUBJECT_GAMING_KEY_ACTION = 44;
	public final static int SUBJECT_GAMING_VALUE_CHAT = 440;
	public final static int SUBJECT_GAMING_VALUE_GAME = 441;
	public final static int SUBJECT_GAMING_VALUE_WINNER = 442;
	public final static int SUBJECT_GAMING_KEY_GAMEACTION = 45;
	public final static int SUBJECT_GAMING_KEY_CHATACTION = 46;
	public final static int SUBJECT_GAMING_KEY_WINNER = 48;
	
	public final static String databaseUrl = "jdbc:postgresql://localhost/irgc01";
    public final static String databaseUser = "postgres";
    public final static String databasePassword = "12345678";
	
    private final static int port = 5000;
	/**
	 * TODO: this is not good idea :/
	 */
    public static ArrayList<Player> players = new ArrayList<Player>();
	
	public class PlayerHandler implements Runnable {
		Player player;
		
		public PlayerHandler(Player player) {
				this.player = player;
		}
		
		public void run() {
			Object obj;
			try {
				while ((obj = player.getObjectInputStream().readObject()) != null)
					parseMessage((JSONObject)obj);
			} catch(Exception ex) {
				ex.printStackTrace();
			}
		}
		
		public void parseMessage(JSONObject msg) {
			JSONObject data = new JSONObject();
			switch ((int)msg.get(SUBJECT_KEY)) {
			case SUBJECT_VALUE_SIGNIN:
				data = SigninController.checkSignin(msg);
				sendObjectToPlayer(data);
				/**
				 * TODO: this is not good idea too :/
				 */
				if((int)data.get(SUBJECT_SIGNIN_KEY_ISACCEPTED) == SUBJECT_SIGNIN_VALUE_ACCEPTED) {
					player.setName((String)data.get(SUBJECT_SIGNIN_KEY_USERNAME));
					players.add(player);
				}
				break;
			case SUBJECT_VALUE_SIGNUP:
				data = SignupController.checkSignup(msg);
				sendObjectToPlayer(data);
				break;
			case SUBJECT_VALUE_GAMEREQUEST:
				data = GameController.gameRequested(msg);
				/**
				 * emmmm i don like it
				 */
				sendObjectToPlayer(data);//player2 is itself
				if((int)data.get(SUBJECT_GAMEREQUEST_KEY_STATE) == SUBJECT_GAMEREQUEST_VALUE_GO)
					sendObjectToPlayer(data, (String)data.get(SUBJECT_GAMEREQUEST_KEY_PLAYER1));
				break;
			case SUBJECT_VALUE_GAMING :
				data = GameController.gaming(msg,player.getName());
				for(Game g: GameController.concurrentGames) {
					if(g.p1.equals(player.getName())) {	
						sendObjectToPlayer(data, g.p2);
						break;
					}
					if(g.p2.equals(player.getName())) {
						sendObjectToPlayer(data, g.p1);
						break;
					}
				}
				if((int)data.get(SUBJECT_GAMING_KEY_ACTION) == SUBJECT_GAMING_VALUE_WINNER)
					sendObjectToPlayer(data);
			default:
				break;
			}
		}
		
		private void sendObjectToPlayer(Object obj) {
			try {
				player.getObjectOutputStream().writeObject(obj);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		private void sendObjectToPlayer(Object obj,String playerName) {
			try {
				for (Player p : players)
					if(p.getName().equals(playerName)) {
						p.getObjectOutputStream().writeObject(obj);
						break;
					}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public void go() {
		try {
			ServerSocket serverSocket = new ServerSocket(port);
			while(true) {
				Socket socket = serverSocket.accept();
				ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
				ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
				
				Player p = new Player(socket, oos, ois);
				Thread t = new Thread(new PlayerHandler(p));
				t.start();
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
	
	public static void main (String[] args) {
		new Server().go();
	}
}